/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "androidfw/ResourceTypes.h"

#include "utils/Log.h"
#include "utils/String8.h"
#include "utils/Vector.h"

#include "TestHelpers.h"
#include "gtest/gtest.h"

namespace android {

static ResTable_config selectBest(const ResTable_config& target,
                                  const Vector<ResTable_config>& configs) {
  ResTable_config bestConfig;
  memset(&bestConfig, 0, sizeof(bestConfig));
  const size_t configCount = configs.size();
  for (size_t i = 0; i < configCount; i++) {
    const ResTable_config& thisConfig = configs[i];
    if (!thisConfig.match(target)) {
      continue;
    }

    if (thisConfig.isBetterThan(bestConfig, &target)) {
      bestConfig = thisConfig;
    }
  }
  return bestConfig;
}

static ResTable_config buildDensityConfig(int density) {
  ResTable_config config;
  memset(&config, 0, sizeof(config));
  config.density = uint16_t(density);
  config.sdkVersion = 4;
  return config;
}

TEST(ConfigTest, shouldSelectBestDensity) {
  ResTable_config deviceConfig;
  memset(&deviceConfig, 0, sizeof(deviceConfig));
  deviceConfig.density = ResTable_config::DENSITY_XHIGH;
  deviceConfig.sdkVersion = 21;

  Vector<ResTable_config> configs;

  ResTable_config expectedBest =
      buildDensityConfig(ResTable_config::DENSITY_HIGH);
  configs.add(expectedBest);
  ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));

  expectedBest = buildDensityConfig(ResTable_config::DENSITY_XXHIGH);
  configs.add(expectedBest);
  ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));

  expectedBest = buildDensityConfig(int(ResTable_config::DENSITY_XXHIGH) - 20);
  configs.add(expectedBest);
  ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));

  configs.add(buildDensityConfig(int(ResTable_config::DENSITY_HIGH) + 20));
  ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));

  configs.add(buildDensityConfig(int(ResTable_config::DENSITY_XHIGH) - 1));
  ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));

  expectedBest = buildDensityConfig(ResTable_config::DENSITY_XHIGH);
  configs.add(expectedBest);
  ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));

  expectedBest = buildDensityConfig(ResTable_config::DENSITY_ANY);
  expectedBest.sdkVersion = 21;
  configs.add(expectedBest);
  ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
}

TEST(ConfigTest, shouldSelectBestDensityWhenNoneSpecified) {
  ResTable_config deviceConfig;
  memset(&deviceConfig, 0, sizeof(deviceConfig));
  deviceConfig.sdkVersion = 21;

  Vector<ResTable_config> configs;
  configs.add(buildDensityConfig(ResTable_config::DENSITY_HIGH));

  ResTable_config expectedBest =
      buildDensityConfig(ResTable_config::DENSITY_MEDIUM);
  configs.add(expectedBest);
  ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));

  expectedBest = buildDensityConfig(ResTable_config::DENSITY_ANY);
  configs.add(expectedBest);
  ASSERT_EQ(expectedBest, selectBest(deviceConfig, configs));
}

TEST(ConfigTest, shouldMatchRoundQualifier) {
  ResTable_config deviceConfig;
  memset(&deviceConfig, 0, sizeof(deviceConfig));

  ResTable_config roundConfig;
  memset(&roundConfig, 0, sizeof(roundConfig));
  roundConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;

  EXPECT_FALSE(roundConfig.match(deviceConfig));

  deviceConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;

  EXPECT_TRUE(roundConfig.match(deviceConfig));

  deviceConfig.screenLayout2 = ResTable_config::SCREENROUND_NO;

  EXPECT_FALSE(roundConfig.match(deviceConfig));

  ResTable_config notRoundConfig;
  memset(&notRoundConfig, 0, sizeof(notRoundConfig));
  notRoundConfig.screenLayout2 = ResTable_config::SCREENROUND_NO;

  EXPECT_TRUE(notRoundConfig.match(deviceConfig));
}

TEST(ConfigTest, RoundQualifierShouldHaveStableSortOrder) {
  ResTable_config defaultConfig;
  memset(&defaultConfig, 0, sizeof(defaultConfig));

  ResTable_config longConfig = defaultConfig;
  longConfig.screenLayout = ResTable_config::SCREENLONG_YES;

  ResTable_config longRoundConfig = longConfig;
  longRoundConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;

  ResTable_config longRoundPortConfig = longConfig;
  longRoundPortConfig.orientation = ResTable_config::ORIENTATION_PORT;

  EXPECT_TRUE(longConfig.compare(longRoundConfig) < 0);
  EXPECT_TRUE(longConfig.compareLogical(longRoundConfig) < 0);
  EXPECT_TRUE(longRoundConfig.compare(longConfig) > 0);
  EXPECT_TRUE(longRoundConfig.compareLogical(longConfig) > 0);

  EXPECT_TRUE(longRoundConfig.compare(longRoundPortConfig) < 0);
  EXPECT_TRUE(longRoundConfig.compareLogical(longRoundPortConfig) < 0);
  EXPECT_TRUE(longRoundPortConfig.compare(longRoundConfig) > 0);
  EXPECT_TRUE(longRoundPortConfig.compareLogical(longRoundConfig) > 0);
}

TEST(ConfigTest, ScreenShapeHasCorrectDiff) {
  ResTable_config defaultConfig;
  memset(&defaultConfig, 0, sizeof(defaultConfig));

  ResTable_config roundConfig = defaultConfig;
  roundConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;

  EXPECT_EQ(defaultConfig.diff(roundConfig),
            ResTable_config::CONFIG_SCREEN_ROUND);
}

TEST(ConfigTest, RoundIsMoreSpecific) {
  ResTable_config deviceConfig;
  memset(&deviceConfig, 0, sizeof(deviceConfig));
  deviceConfig.screenLayout2 = ResTable_config::SCREENROUND_YES;
  deviceConfig.screenLayout = ResTable_config::SCREENLONG_YES;

  ResTable_config targetConfigA;
  memset(&targetConfigA, 0, sizeof(targetConfigA));

  ResTable_config targetConfigB = targetConfigA;
  targetConfigB.screenLayout = ResTable_config::SCREENLONG_YES;

  ResTable_config targetConfigC = targetConfigB;
  targetConfigC.screenLayout2 = ResTable_config::SCREENROUND_YES;

  EXPECT_TRUE(targetConfigB.isBetterThan(targetConfigA, &deviceConfig));
  EXPECT_TRUE(targetConfigC.isBetterThan(targetConfigB, &deviceConfig));
}

TEST(ConfigTest, ScreenIsWideGamut) {
  ResTable_config defaultConfig;
  memset(&defaultConfig, 0, sizeof(defaultConfig));

  ResTable_config wideGamutConfig = defaultConfig;
  wideGamutConfig.colorMode = ResTable_config::WIDE_COLOR_GAMUT_YES;

  EXPECT_EQ(defaultConfig.diff(wideGamutConfig), ResTable_config::CONFIG_COLOR_MODE);
}

TEST(ConfigTest, ScreenIsHdr) {
  ResTable_config defaultConfig;
  memset(&defaultConfig, 0, sizeof(defaultConfig));

  ResTable_config hdrConfig = defaultConfig;
  hdrConfig.colorMode = ResTable_config::HDR_YES;

  EXPECT_EQ(defaultConfig.diff(hdrConfig), ResTable_config::CONFIG_COLOR_MODE);
}

TEST(ConfigTest, GrammaticalGender) {
  ResTable_config defaultConfig = {};
  ResTable_config masculine = {};
  masculine.grammaticalInflection = ResTable_config::GRAMMATICAL_GENDER_MASCULINE;

  EXPECT_EQ(defaultConfig.diff(masculine), ResTable_config::CONFIG_GRAMMATICAL_GENDER);

  ResTable_config feminine = {};
  feminine.grammaticalInflection = ResTable_config::GRAMMATICAL_GENDER_FEMININE;

  EXPECT_EQ(defaultConfig.diff(feminine), ResTable_config::CONFIG_GRAMMATICAL_GENDER);
  EXPECT_EQ(masculine.diff(feminine), ResTable_config::CONFIG_GRAMMATICAL_GENDER);
}

}  // namespace android.
